TypeScriptãã³ãã¬ãŒããªãã©ã«åãæ¢æ±ããå ç¢ãªæååæ€èšŒãšåå®å šæ§ãå®çŸããã©ã³ã¿ã€ã æ€èšŒãšã³ãžã³ãæ§ç¯ããŸããå®è¡æã«å®çŸ©ããããã³ãã¬ãŒããªãã©ã«åã«å¯ŸããŠæååãæ€èšŒããããšã§ããšã©ãŒã鲿¢ããæ¹æ³ãåŠã³ãŸãããã
TypeScriptãã³ãã¬ãŒããªãã©ã«æ€èšŒãšã³ãžã³: ã©ã³ã¿ã€ã æååæ€èšŒ
TypeScriptã®ãã³ãã¬ãŒããªãã©ã«åã¯ã匷åãªã³ã³ãã€ã«ææååæäœãšåå®å šæ§ãæäŸããŸãããããããããã®ãã§ãã¯ã¯ã³ã³ãã€ã«æã«éå®ãããŸãããã®ããã°èšäºã§ã¯ãTypeScriptã®ãã³ãã¬ãŒããªãã©ã«åã«å¯Ÿããã©ã³ã¿ã€ã æ€èšŒãšã³ãžã³ãæ§ç¯ããæ¹æ³ãæ¢ããå ç¢ãªæååæ€èšŒãå¯èœã«ããããã°ã©ã å®è¡äžã®æœåšçãªãšã©ãŒãé²ãæ¹æ³ã説æããŸãã
TypeScriptãã³ãã¬ãŒããªãã©ã«åã®æŠèŠ
ãã³ãã¬ãŒããªãã©ã«åã䜿çšãããšããªãã©ã«å€ããŠããªã³ãåæšè«ã«åºã¥ããŠç¹å®ã®æååã®åœ¢ç¶ãå®çŸ©ã§ããŸããããã«ãããç¹ã«æ§é åããŒã¿ããã¡ã€ã³åºæèšèªãæ±ãå Žåã«åœ¹ç«ã€ãæ£ç¢ºãªåãã§ãã¯ãšãªãŒãã³ã³ããªãŒããå¯èœã«ãªããŸãã
ããšãã°ãé貚ã³ãŒãã衚ãåãèããŠã¿ãŸãããã
type CurrencyCode = "USD" | "EUR" | "GBP";
type FormattedCurrencyString = `${CurrencyCode}-${number}`;
const validCurrency: FormattedCurrencyString = "USD-100"; // OK
const invalidCurrency: FormattedCurrencyString = "CAD-50"; // Type error at compile time
ãã®äŸã¯ãTypeScriptãã³ã³ãã€ã«æã«FormattedCurrencyStringåãã©ã®ããã«åŒ·å¶ãããã瀺ããŠããŸããããããé貚ã³ãŒããå€éšãœãŒã¹ïŒäŸïŒãŠãŒã¶ãŒå
¥åãAPIå¿çïŒããæ¥ãå Žåãåå®å
šæ§ã確ä¿ããããã«ã©ã³ã¿ã€ã æ€èšŒãå¿
èŠã§ãã
ã©ã³ã¿ã€ã æ€èšŒã®å¿ èŠæ§
TypeScriptã¯åªããã³ã³ãã€ã«æã®åãã§ãã¯ãæäŸããŸãããå®è¡æã«å€éšãœãŒã¹ããåãåã£ãããŒã¿ã®æå¹æ§ãä¿èšŒããããšã¯ã§ããŸãããã³ã³ãã€ã«æã®åã®ã¿ã«äŸåãããšãäºæãã¬ãšã©ãŒãè匱æ§ã«ã€ãªããå¯èœæ§ããããŸãã
次ã®ã·ããªãªãèããŠã¿ãŸãããã
function processCurrency(currencyString: FormattedCurrencyString) {
// ... some logic that assumes the string is correctly formatted
}
const userInput = "CAD-50"; // Assume this comes from user input
// This will compile, but will cause a runtime error if the logic inside
// `processCurrency` relies on the format.
processCurrency(userInput as FormattedCurrencyString);
ãã®å ŽåãuserInputãFormattedCurrencyStringã«ãã£ã¹ãããŠãããTypeScriptã®ã³ã³ãã€ã«æãã§ãã¯ããã€ãã¹ããŠããŸããããprocessCurrencyãæååãæ£ãããã©ãŒããããããŠããããšã«äŸåããŠããå Žåãå®è¡æãšã©ãŒãçºçããŸãã
ã©ã³ã¿ã€ã æ€èšŒã¯ãå®è¡æã«åãåã£ãããŒã¿ãæåŸ ãããTypeScriptã®åã«æºæ ããŠããããšã確èªããããšã§ããã®ã®ã£ãããåããŸãã
ãã³ãã¬ãŒããªãã©ã«æ€èšŒãšã³ãžã³ã®æ§ç¯
æ£èŠè¡šçŸãšTypeScriptã®åã·ã¹ãã ã䜿çšããŠãã©ã³ã¿ã€ã æ€èšŒãšã³ãžã³ãæ§ç¯ã§ããŸãããã®ãšã³ãžã³ã¯ããã³ãã¬ãŒããªãã©ã«åãšæååãå ¥åãšããŠåãåãããã®æååãåã«äžèŽãããã©ãããè¿ããŸãã
ã¹ããã1: ã©ã³ã¿ã€ã æ€èšŒã®ããã®åã®å®çŸ©
ãŸãããã³ãã¬ãŒããªãã©ã«åã®ã©ã³ã¿ã€ã çžåœã衚ãããšãã§ãããžã§ããªãã¯åãå¿ èŠã§ãããã®åã¯ããªãã©ã«ããŠããªã³ãåãã©ã¡ãŒã¿ãŒãªã©ãããŸããŸãªçš®é¡ã®ãã³ãã¬ãŒããªãã©ã«ãåŠçã§ããå¿ èŠããããŸãã
type TemplateLiteralToRegex =
T extends `${infer Start}${infer Middle}${infer End}`
? Start extends string
? Middle extends string
? End extends string
? TemplateLiteralToRegexStart & TemplateLiteralToRegexMiddle & TemplateLiteralToRegex
: never
: never
: never
: TemplateLiteralToRegexStart;
type TemplateLiteralToRegexStart = T extends `${infer Literal}` ? Literal : string;
type TemplateLiteralToRegexMiddle = T extends `${infer Literal}` ? Literal : string;
ãã®ååž°çãªåå®çŸ©ã¯ããã³ãã¬ãŒããªãã©ã«ãæ§æèŠçŽ ã«åè§£ããåéšåãæ£èŠè¡šçŸãã¿ãŒã³ã«å€æããŸãã
ã¹ããã2: æ€èšŒé¢æ°ã®å®è£
次ã«ããã³ãã¬ãŒããªãã©ã«åãšæ€èšŒããæååãå
¥åãšããŠåãåãæ€èšŒé¢æ°ãå®è£
ããŸãããã®é¢æ°ã¯ãTemplateLiteralToRegexã«ãã£ãŠçæãããæ£èŠè¡šçŸã䜿çšããŠæååããã¹ãããŸãã
function isValid(str: string, templateType: T): boolean {
const regexPattern = `^${convertTemplateLiteralToRegex(templateType)}$`;
const regex = new RegExp(regexPattern);
return regex.test(str);
}
function convertTemplateLiteralToRegex(templateType: T): string {
// Basic conversion for literal strings - extend this for more complex scenarios
return templateType.replace(/[.*+?^${}()|[\]]/g, '\\$&'); // Escape special regex characters
}
ãã®é¢æ°ã¯ãç¹æ®ãªæ£èŠè¡šçŸæåããšã¹ã±ãŒããããã³ãã¬ãŒããªãã©ã«åããæ£èŠè¡šçŸãäœæãããã®æ£èŠè¡šçŸã«å¯ŸããŠæååããã¹ãããŸãã
ã¹ããã3: æ€èšŒãšã³ãžã³ã®äœ¿çš
ããã§ãisValid颿°ã䜿çšããŠãå®è¡æã«æååããã³ãã¬ãŒããªãã©ã«åã«å¯ŸããŠæ€èšŒã§ããŸãã
type CurrencyCode = "USD" | "EUR" | "GBP";
type FormattedCurrencyString = `${CurrencyCode}-${number}`;
const userInput1 = "USD-100";
const userInput2 = "CAD-50";
console.log(`'${userInput1}' is valid: ${isValid(userInput1, "USD-100" )}`); // true
console.log(`'${userInput2}' is valid: ${isValid(userInput2, "USD-100")}`); // false
console.log(`'${userInput1}' is valid: ${isValid(userInput1, `USD-${100}`)}`); // true
console.log(`'${userInput2}' is valid: ${isValid(userInput2, `USD-${100}`)}`); // false
ãã®äŸã¯ãisValid颿°ã䜿çšããŠããŠãŒã¶ãŒå
¥åãFormattedCurrencyStringåã«å¯ŸããŠæ€èšŒããæ¹æ³ã瀺ããŠããŸããåºåã¯ãæå®ããããã³ãã¬ãŒããªãã©ã«ã«åºã¥ããŠãå
¥åæååãæå¹ãšèŠãªããããã©ããã瀺ããŸãã
é«åºŠãªæ€èšŒã·ããªãª
åºæ¬çãªæ€èšŒãšã³ãžã³ã¯ããŠããªã³ãæ¡ä»¶åãååž°åãªã©ã®ããè€éãªã·ããªãªãåŠçããããã«æ¡åŒµã§ããŸãã
ãŠããªã³ã®åŠç
ãŠããªã³ãåŠçããã«ã¯ãTemplateLiteralToRegexåã倿ŽããŠããŠããªã³ã¡ã³ããŒã®ããããã«äžèŽããæ£èŠè¡šçŸãçæã§ããŸãã
type CurrencyCode = "USD" | "EUR" | "GBP";
type FormattedCurrencyString = `${CurrencyCode}-${number}`;
function isValidCurrencyCode(str: string, templateType: T): boolean {
const currencyCodes: CurrencyCode[] = ["USD", "EUR", "GBP"];
return currencyCodes.includes(str as CurrencyCode);
}
function isValidUnionFormattedCurrencyString(str: string): boolean {
const parts = str.split('-');
if(parts.length !== 2) return false;
const [currencyCode, amount] = parts;
if (!isValidCurrencyCode(currencyCode, currencyCode)) return false;
if (isNaN(Number(amount))) return false;
return true;
}
console.log(`'USD-100' is valid formatted string: ${isValidUnionFormattedCurrencyString('USD-100')}`);
console.log(`'CAD-50' is valid formatted string: ${isValidUnionFormattedCurrencyString('CAD-50')}`);
æ¡ä»¶åã®åŠç
æ¡ä»¶åã¯ãå®è¡æã«æ¡ä»¶ãè©äŸ¡ããçµæã«åºã¥ããŠç°ãªãæ£èŠè¡šçŸãçæããããšã§åŠçã§ããŸãã
type IsString = T extends string ? true : false;
// This example requires more advanced logic and isn't fully implementable using simple regex.
// Runtime type guards offer a more robust solution in this specific scenario.
// The below code is illustrative and would need adaptation to handle complex conditional types.
function isString(value: any): value is string {
return typeof value === 'string';
}
function isValidConditionalType(value: any): boolean {
return isString(value);
}
console.log(`'hello' is a string: ${isValidConditionalType('hello')}`);
console.log(`123 is a string: ${isValidConditionalType(123)}`);
ååž°åã®åŠç
ååž°åã¯ãæ£èŠè¡šçŸãã¿ãŒã³ãçæããååž°é¢æ°ãå®çŸ©ããããšã§åŠçã§ããŸãããã ããç¡éååž°ãšã¹ã¿ãã¯ãªãŒããŒãããŒãšã©ãŒãé¿ããããæ³šæããŠãã ãããæ·±ãååž°ã®å Žåãé©åãªå¶éãèšããå埩ã¢ãããŒããäžå¯æ¬ ã§ãã
æ£èŠè¡šçŸä»¥å€ã®éžæè¢
æ£èŠè¡šçŸã¯æååæ€èšŒã®ããã®åŒ·åãªããŒã«ã§ãããè€éã§ä¿å®ãé£ããå ŽåããããŸããã©ã³ã¿ã€ã æ€èšŒãžã®ä»ã®ã¢ãããŒãã«ã¯ã次ã®ãããªãã®ããããŸãã
- ã«ã¹ã¿ã æ€èšŒé¢æ°: ã¢ããªã±ãŒã·ã§ã³ã®èŠä»¶ã«åºã¥ããŠç¹å®ã®åãæ€èšŒããã«ã¹ã¿ã 颿°ãäœæããŸãã
- åã¬ãŒã: åã¬ãŒãã䜿çšããŠãå®è¡æã«å€æ°ã®åãçµã蟌ã¿ãŸãã
- æ€èšŒã©ã€ãã©ãª: ZodãYupãªã©ã®æ¢åã®æ€èšŒã©ã€ãã©ãªã掻çšããŠãæ€èšŒããã»ã¹ãç°¡çŽ åããŸãã
ããšãã°Zodã¯ãæ€èšŒã©ã³ã¿ã€ã ã«å€æãããã¹ããŒãããŒã¹ã®å®£èšãæäŸããŸãã
import { z } from 'zod';
const CurrencyCodeSchema = z.enum(['USD', 'EUR', 'GBP']);
const FormattedCurrencyStringSchema = z.string().regex(new RegExp(`^${CurrencyCodeSchema.enum.USD}|${CurrencyCodeSchema.enum.EUR}|${CurrencyCodeSchema.enum.GBP}-[0-9]+$`));
try {
const validCurrency = FormattedCurrencyStringSchema.parse("USD-100");
console.log("Valid Currency:", validCurrency);
} catch (error) {
console.error("Invalid Currency:", error);
}
try {
const invalidCurrency = FormattedCurrencyStringSchema.parse("CAD-50");
console.log("Valid Currency:", invalidCurrency); //This won't execute if parse fails.
} catch (error) {
console.error("Invalid Currency:", error);
}
ã©ã³ã¿ã€ã æ€èšŒã®ãã¹ããã©ã¯ãã£ã¹
ã©ã³ã¿ã€ã æ€èšŒãå®è£ ããéã«ã¯ã以äžã®ãã¹ããã©ã¯ãã£ã¹ã念é ã«çœ®ããŠãã ããã
- å¢çã§ã®æ€èšŒ: ããŒã¿ãã·ã¹ãã ã«å ¥ã£ãçŽåŸïŒäŸïŒãŠãŒã¶ãŒå ¥åãAPIå¿çïŒã«æ€èšŒããŸãã
- æç¢ºãªãšã©ãŒã¡ãã»ãŒãžã®æäŸ: ãŠãŒã¶ãŒãå ¥åãç¡å¹ã§ããçç±ãçè§£ããã®ã«åœ¹ç«ã€ãæ å ±éã®ãããšã©ãŒã¡ãã»ãŒãžãçæããŸãã
- äžè²«ããæ€èšŒæŠç¥ã®äœ¿çš: ããŒã¿ã®äžè²«æ§ã確ä¿ããããã«ãã¢ããªã±ãŒã·ã§ã³å šäœã§äžè²«ããæ€èšŒæŠç¥ãæ¡çšããŸãã
- æ€èšŒããžãã¯ã®ãã¹ã: æå¹ãªããŒã¿ãšç¡å¹ãªããŒã¿ãæ£ããèå¥ããããšã確èªããããã«ãæ€èšŒããžãã¯ã培åºçã«ãã¹ãããŸãã
- ããã©ãŒãã³ã¹ãšã»ãã¥ãªãã£ã®ãã©ã³ã¹: ããã©ãŒãã³ã¹ã®ããã«æ€èšŒããžãã¯ãæé©åãã€ã€ãã»ãã¥ãªãã£è匱æ§ã广çã«é²ãããšãä¿èšŒããŸãããµãŒãã¹æåŠã«ã€ãªããé床ã«è€éãªæ£èŠè¡šçŸã¯é¿ããŠãã ããã
åœéåã®èæ ®äºé
ã°ããŒãã«ãªã³ã³ããã¹ãã§æååæ€èšŒãæ±ãå ŽåãåœéåïŒi18nïŒãšããŒã«ã©ã€ãºïŒl10nïŒãèæ ®ããå¿ èŠããããŸããç°ãªããã±ãŒã«ã§ã¯ãæ¥ä»ãæ°å€ãé貚å€ãªã©ã®æååã®æžåŒèšå®ã«ãŒã«ãç°ãªãå ŽåããããŸãã
ããšãã°ããŠãŒãïŒâ¬ïŒã®é貚èšå·ã¯ããã±ãŒã«ã«ãã£ãŠéé¡ã®åãŸãã¯åŸã«è¡šç€ºãããå ŽåããããŸããåæ§ã«ãå°æ°ç¹åºåãèšå·ã¯ããªãªãïŒ.ïŒãŸãã¯ã³ã³ãïŒ,ïŒã®å ŽåããããŸãã
ãããã®ããªãšãŒã·ã§ã³ãåŠçããã«ã¯ããã±ãŒã«ã«å¿ããããŒã¿ã®æžåŒèšå®ãšè§£æã®ããã®APIãæäŸããIntlã®ãããªåœéåã©ã€ãã©ãªã䜿çšã§ããŸããäŸãã°ãåã®äŸãç°ãªãé貚圢åŒãåŠçããããã«é©å¿ãããããšãã§ããŸãã
function isValidCurrencyString(currencyString: string, locale: string): boolean {
try {
const formatter = new Intl.NumberFormat(locale, { style: 'currency', currency: currencyString.substring(0,3) }); //Very basic example
//Attempt to parse the currency using formatter. This example is intentionally very simple.
return true;
} catch (error) {
return false;
}
}
console.log(`USD-100 is valid for en-US: ${isValidCurrencyString('USD-100', 'en-US')}`);
console.log(`EUR-100 is valid for fr-FR: ${isValidCurrencyString('EUR-100', 'fr-FR')}`);
ãã®ã³ãŒãã¹ããããã¯åºæ¬çãªäŸã瀺ããŠããŸããé©åãªåœéåã«ã¯ããã培åºããåŠçãå¿ èŠã§ãããç°ãªããã±ãŒã«éã§ã®éè²šã®æžåŒèšå®ãšæ€èšŒã®ããã«ç¹å¥ã«èšèšãããå€éšã©ã€ãã©ãªãAPIãå©çšããå¯èœæ§ããããŸãã
çµè«
ã©ã³ã¿ã€ã æ€èšŒã¯ãå ç¢ã§ä¿¡é Œæ§ã®é«ãTypeScriptã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããããã®äžå¯æ¬ ãªéšåã§ããTypeScriptã®ãã³ãã¬ãŒããªãã©ã«åãæ£èŠè¡šçŸãŸãã¯ä»£æ¿ã®æ€èšŒæ¹æ³ãšçµã¿åãããããšã§ãå®è¡æã«æååã®æå¹æ§ãæ€èšŒããããã®åŒ·åãªãšã³ãžã³ãäœæã§ããŸãã
ãã®ã¢ãããŒãã«ãããåå®å šæ§ãåäžããäºæãã¬ãšã©ãŒã鲿¢ãããã³ãŒãå šäœã®å質ãåäžããŸããããè€éãªã¢ããªã±ãŒã·ã§ã³ãæ§ç¯ããéã«ã¯ãããŒã¿ãæåŸ ãããåãšåœ¢åŒã«æºæ ããŠããããšã確èªããããã«ãã©ã³ã¿ã€ã æ€èšŒãçµã¿èŸŒãããšãæ€èšããŠãã ããã
ãããªãæ¢æ±
- ããè€éãªæ€èšŒã·ããªãªã®ããã«ãé«åºŠãªæ£èŠè¡šçŸãã¯ããã¯ãæ¢æ±ããŠãã ããã
- ã¹ããŒãããŒã¹ã®æ€èšŒã®ããã«ãZodãYupãªã©ã®æ€èšŒã©ã€ãã©ãªã調ã¹ãŠãã ããã
- TypeScriptåããæ€èšŒé¢æ°ãèªåçã«çæããããã«ãã³ãŒãçæãã¯ããã¯ã®äœ¿çšãæ€èšããŠãã ããã
- ãã±ãŒã«ã«å¿ããããŒã¿ãåŠçããããã«ãåœéåã©ã€ãã©ãªãšAPIãåŠç¿ããŠãã ããã